# 变异和交叉算子
import random
from src.ga.interpreter import dec2bin, bin2dec


def byte_mutation(tensor, m_type, n):
    """
        m_type包括：
            - 取反 reverse
            - 左移1位 left
            - 右移1位 right
            - 左移2位 left2
            - 右移2位 right2
            - 删除 delete
            - 增加 add
        n可取：0,1,2,3
    """
    if n not in range(0,4):
        return ''
    if m_type == 'reverse':
        for i in range(8):
            tensor[n * 8 + i] = '1' if tensor[n * 8 + i] == '0' else '0'
    elif m_type == 'left':
        for i in range(7):
            tensor[n * 8 + 6 - i] = tensor[n * 8 + 7 - i]
        tensor[n * 8 + 7] = '0'
    elif m_type == 'left2':
        for i in range(6):
            tensor[n * 8 + 5 - i] = tensor[n * 8 + 7 - i]
        tensor[n * 8 + 7] = '0'
        tensor[n * 8 + 6] = '0'
    elif m_type == 'right':
        for i in range(7):
            tensor[n * 8 + i + 1] = tensor[n * 8 + i]
        tensor[n * 8] = tensor[n * 8 + 1]
    elif m_type == 'right2':
        for i in range(6):
            tensor[n * 8 + i + 2] = tensor[n * 8 + i]
        tensor[n * 8 + 1] = tensor[n * 8 + 2]
        tensor[n * 8] = tensor[n * 8 + 1]
    elif m_type == 'delete':
        tensor[n*8: n*8 + 8] = 'X'
        tensor = tensor.replace('X', '')
        for i in range(8):
            tensor = tensor + '1'
    elif m_type == 'add':
        new_one = ''
        for i in range(8):
            new_one = new_one + str(random.randint(0,1))
        tensor = tensor[0:n * 8] + new_one + tensor[n*8:-8]
    else:
        return ''
    return tensor


def bit_mutation(tensor, m_type, n):
    """
        m_type包括：
            - 取反 reverse
            - 删除 delete
            - 增加 add
        n可取：0-31
    """
    if n not in range(32):
        return ''
    if m_type == 'reverse':
        tensor[n] = '1' if tensor[n] == '0' else '0'
    elif m_type == 'delete':
        tensor[n] = 'X'
        tensor = tensor.replace('X', '')
        tensor = tensor + '1'
    elif m_type == 'add':
        tensor = tensor[0:n] + str(random.randint(0,1)) + tensor[n:-1]
    else:
        return ''
    return tensor


def noise_mutation(tensor):
    random_pattern = random.randint(0,1)
    if random_pattern == 0:
        noise = random.gauss(0, 1)
        res = bin2dec(tensor) + noise
        res = dec2bin(res)
    else:
        noise = random.unifor(0, 1)
        res = bin2dec(tensor) + noise
        res = dec2bin(res)
    return res


def gene_mutation(tensor1, tensor2, n):
    if n not in range(4):
        return tensor1, tensor2
    tmp = tensor1[n * 8:n * 8 + 8]
    tensor1[n * 8:n * 8 + 8] = tensor2[n * 8:n * 8 + 8]
    tensor2[n * 8:n * 8 + 8] = tmp
    return tensor1, tensor2
